{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "dd84267c",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np \n",
    "import torch \n",
    "# 导入 PyTorch 内置的 mnist 数据 \n",
    "from torchvision.datasets import mnist \n",
    "#导入预处理模块 \n",
    "import torchvision.transforms as transforms \n",
    "from torch.utils.data import DataLoader \n",
    "#导入nn及优化器 \n",
    "import torch.nn.functional as F \n",
    "import torch.optim as optim\n",
    "from torch import nn"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "be3a9840",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义一些超参数 \n",
    "train_batch_size = 64 \n",
    "test_batch_size = 128 \n",
    "learning_rate = 0.01 \n",
    "num_epoches = 20 \n",
    "lr = 0.01\n",
    "momentum = 0.5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "7137a27b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz\n",
      "Downloading http://211.69.138.66/cache/11/02/yann.lecun.com/34152be34c1115808d82493371362afe/train-images-idx3-ubyte.gz to ./data/MNIST/raw/train-images-idx3-ubyte.gz\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 9912422/9912422 [00:01<00:00, 9015301.19it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting ./data/MNIST/raw/train-images-idx3-ubyte.gz to ./data/MNIST/raw\n",
      "\n",
      "Downloading http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz\n",
      "Downloading http://211.69.138.66/cache/3/02/yann.lecun.com/32a667c2f3de678798ae039d04726fa1/train-labels-idx1-ubyte.gz to ./data/MNIST/raw/train-labels-idx1-ubyte.gz\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 28881/28881 [00:00<00:00, 5744567.45it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting ./data/MNIST/raw/train-labels-idx1-ubyte.gz to ./data/MNIST/raw\n",
      "\n",
      "Downloading http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Downloading http://211.69.138.66/cache/9/02/yann.lecun.com/b80c4efc17eabb28908f865775412435/t10k-images-idx3-ubyte.gz to ./data/MNIST/raw/t10k-images-idx3-ubyte.gz\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1648877/1648877 [00:00<00:00, 3204025.11it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting ./data/MNIST/raw/t10k-images-idx3-ubyte.gz to ./data/MNIST/raw\n",
      "\n",
      "Downloading http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz\n",
      "Downloading http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz to ./data/MNIST/raw/t10k-labels-idx1-ubyte.gz\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 4542/4542 [00:00<00:00, 8783093.02it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting ./data/MNIST/raw/t10k-labels-idx1-ubyte.gz to ./data/MNIST/raw\n",
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    }
   ],
   "source": [
    "#定义预处理函数，这些预处理依次放在Compose函数中。 \n",
    "transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize([0.5], [0.5])]) \n",
    "#下载数据，并对数据进行预处理 \n",
    "train_dataset = mnist.MNIST('./data', train=True, transform=transform, download=True) \n",
    "test_dataset = mnist.MNIST('./data', train=False, transform=transform) \n",
    "#dataloader是一个可迭代对象，可以使用迭代器一样使用。 \n",
    "train_loader = DataLoader(train_dataset, batch_size=train_batch_size, shuffle=True)\n",
    "test_loader = DataLoader(test_dataset, batch_size=test_batch_size, shuffle=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "4273b33d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAmYAAAGkCAYAAACb5OmoAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAsU0lEQVR4nO3deXSU9b3H8c+EhGxESsK+XJYoUpYgELwIVtlBNpGlIMguSwH1HFsUSstWxWu8teW2oLSXKFLlqlAWgaIUIyrIldBSwIIc0kvAEg0ECUuIZJn7B4fYOL8h80xmkt8k79c5/JFPnjzPd3B+8smT/GZcbrfbLQAAAFS6sMoeAAAAADdQzAAAACxBMQMAALAExQwAAMASFDMAAABLUMwAAAAsQTEDAACwBMUMAADAEhQzAAAAS1RqMTt8+LCmTZumxMRERUdHKzo6WnfccYdmzpyp9PT0yhyt3Fwul5YsWeL18z179pTL5Srzz63O4Yu8vDwtWbJEH3zwgcfnlixZIpfLpfPnz5frGv/q1KlTt3w8AwcODNi1YMa6qnrr6tKlS3r22WfVs2dPNWzYULVq1VKHDh30/PPPKz8/P2DXgXesq6q3riRp27Ztmjhxojp06KCIiAi5XK6Ant8f4ZV14dWrV2vu3Lm688479cQTT6hdu3ZyuVw6duyY1q9fr65du+rkyZNKTEysrBGDatWqVbp06VLJx9u3b9czzzyjV155RW3atCnJmzZtWq7r5OXlaenSpZJuLK5ga9SokT755BOPfPPmzXr++ef10EMPBX2G6ox1VTXX1enTp/XrX/9aEyZM0JNPPqlatWrpo48+0pIlS7Rr1y7t2rXLin9QqirWVdVcV5K0adMm7d+/X506dVJkZKQOHjxYIde9lUopZnv37tXs2bM1ePBgbdiwQTVr1iz5XO/evTVnzhy9/fbbio6OvuV58vLyFBMTE+xxg6Jt27alPj5+/LgkqX379kpOTvb6dbY/5sjISHXr1s0jX7BggWJiYvTwww9XwlTVA+uq6q6rli1b6tSpU4qNjS3JevfurdjYWM2bN0979+7VvffeW4kTVl2sq6q7riTp97//vcLCbvzwcO7cuVYUs0r5Ueby5ctVo0YNrV69utST/F+NHj1ajRs3Lvl48uTJqlWrlo4cOaL+/fsrLi5Offr0kSRduHBBs2fPVpMmTVSzZk21atVKCxcu1DfffFPy9Td/xPbqq696XOu7t2Bv3jL97LPP9PDDD6t27dpq0KCBpk6dqtzc3FJfe+nSJU2fPl0JCQmqVauWBg4cqBMnTpTjb+dbN+f4y1/+olGjRqlOnTol35H17NnT+B3F5MmT1aJFi5LHXK9ePUnS0qVLS243T548udTXfPXVV2U+zvLIyMjQnj179MMf/lC33XZbwM6L0lhXvgnFdRUbG1uqlN109913S5LOnDnj13lRNtaVb0JxXUkqKWU2qfA7ZkVFRUpLS1NycrIaNWrk6GuvX7+uYcOGaebMmZo/f74KCwuVn5+vXr16KSMjQ0uXLlVSUpI++ugjPffcczp06JC2b9/u96wjR47UmDFjNG3aNB05ckQLFiyQJKWmpkqS3G63hg8frn379mnRokXq2rWr9u7dqwceeMDva5qMGDFCY8eO1axZs3T16lWfv65Ro0bauXOnBg4cqGnTpunRRx+VpJIn/01lPU7pxqJbunSp0tLSHN9iTk1NldvtLrk+Ao915VyorytJev/99yVJ7dq1c/y1KBvryrmqsK4qW4UXs/Pnz+vatWtq3ry5x+eKiorkdrtLPq5Ro0ap35soKCjQokWLNGXKlJJs9erVOnz4sN566y2NHj1aktSvXz/VqlVLTz/9tHbt2qV+/fr5Neu0adM0b948SVLfvn118uRJpaamas2aNXK5XHr33XeVlpamFStW6PHHHy+5ds2aNbVw4UK/rmkyadKkkp+7OxEZGakuXbpIuvGzf9OPGKWyH6d047uK7/738EVRUZHWrl2rNm3aqEePHo4fA3zDunIulNeVdOOX0VNSUvTQQw8pKSnJ8dejbKwr50J9XdnAqnt4Xbp0UURERMmfX/7ylx7HjBw5stTH77//vmJjYzVq1KhS+c3bn7t37/Z7nmHDhpX6OCkpSfn5+crOzpYkpaWlSZLGjx9f6rhx48b5fU2T7z7mQCvrcUrSokWLVFhYqPvvv9/RuXfu3Kl//vOfmjZtWkBmhXOsK7NQXlenTp3SkCFD1KxZM/33f/93QOaFM6wrs1BeV7ao8DtmdevWVXR0tDIzMz0+98YbbygvL09ZWVkef/mSFBMT4/E7Sjk5OWrYsKFHM65fv77Cw8OVk5Pj96wJCQmlPo6MjJQkXbt2reTa4eHhHsc1bNjQ72uaOL2F7lRZj7M81qxZo4iICE2cOLHc54J3rCvnQnVdZWZmqlevXgoPD9fu3bsVHx9frvPBO9aVc6G6rmxS4XfMatSood69eys9PV1ZWVmlPte2bVslJyerQ4cOxq813ZZMSEjQV199VeqWsiRlZ2ersLBQdevWlSRFRUVJUqlfsJRU7oVQWFjocY4vv/zS73OamB53VFSUx2ORFPDXeCmP7Oxsbdu2TcOGDVP9+vUre5wqjXXlXCiuq8zMTPXs2VNut1tpaWnlfnkC3BrryrlQXFe2qZQfZS5YsEBFRUWaNWuWCgoKynWuPn366MqVK9q8eXOp/LXXXiv5vCQ1aNBAUVFROnz4cKnjtmzZ4ve1e/XqJUl6/fXXS+VvvPGG3+f0VYsWLXTixIlST/acnBzt27ev1HGV+d3Ea6+9poKCAn6MWUFYV+Vn87o6ffq0evbsqaKiIr3//vvG33tC4LGuys/mdWWjSnkdsx49emjlypV67LHH1LlzZ82YMUPt2rVTWFiYsrKytHHjRkny6aUVJk6cqJUrV2rSpEk6deqUOnTooI8//ljLly/XoEGD1LdvX0k3Wvwjjzyi1NRUJSYmqmPHjvr000/L9aTs37+/7rvvPj311FO6evWqkpOTtXfvXq1bt87vc/pqwoQJWr16tR555BFNnz5dOTk5SklJ8fg7i4uLU/PmzbVlyxb16dNH8fHxqlu3bskWZV8tW7ZMy5Yt0+7du33+uf2aNWvUrFkzDRgwwNG14B/WVfnZuq6ys7PVq1cvZWVlac2aNcrOzi71OzVNmzbl7lmQsK7Kz9Z1Jd24C33gwAFJN17aSZI2bNgg6UahvNXrtAWNuxIdOnTIPWXKFHfLli3dkZGR7qioKPftt9/unjhxonv37t2ljp00aZI7NjbWeJ6cnBz3rFmz3I0aNXKHh4e7mzdv7l6wYIE7Pz+/1HG5ubnuRx991N2gQQN3bGyse+jQoe5Tp065JbkXL15cctzixYvdktznzp0r9fWvvPKKW5L7//7v/0qyixcvuqdOner+3ve+546JiXH369fPffz4cY9zluXmuQ8cOFDmHDetXbvW/f3vf98dFRXlbtu2rfvNN990T5o0yd28efNSx/35z392d+rUyR0ZGemW5J40aZLjx3nz2LS0NJ8ez969e92S3IsWLfLpeAQO68rz3KG+rtLS0tySvP5x8ncC/7CuPM8d6uvqX7/e9OfmtSuay+3+zg+7AQAAUCmserkMAACA6oxiBgAAYAmKGQAAgCUoZgAAAJagmAEAAFiCYgYAAGAJn15gtri4WGfPnlVcXFzIvls7qia3263Lly+rcePGCgsLre8zWFewFesKCDxf15VPxezs2bNq1qxZwIYDAu3MmTMh98rnrCvYjnUFBF5Z68qnb4Xi4uICNhAQDKH4HA3FmVG9hOJzNBRnRvVS1nPUp2LG7WDYLhSfo6E4M6qXUHyOhuLMqF7Keo6G1i8PAAAAVGEUMwAAAEtQzAAAACxBMQMAALAExQwAAMASFDMAAABLUMwAAAAsQTEDAACwBMUMAADAEhQzAAAAS1DMAAAALEExAwAAsATFDAAAwBIUMwAAAEtQzAAAACwRXtkDAKg+fvKTnxjz6OhoY56UlGTMR40a5fM1X3rpJWP+ySefGPN169b5fG4ACDTumAEAAFiCYgYAAGAJihkAAIAlKGYAAACWoJgBAABYgl2ZAALuzTffNOZOdlPeSnFxsc/Hzpw505j37dvXmO/Zs8eYnz592udrAtVV69atjfnx48eN+RNPPGHMf/Ob3wRsplDDHTMAAABLUMwAAAAsQTEDAACwBMUMAADAEhQzAAAAS7ArE4Dfgr370ttOrnfffdcja9WqlfHYoUOHGvPExERjPn78eGP+3HPPGXMA3+rUqZMx97aT+osvvgjmOCGJO2YAAACWoJgBAABYgmIGAABgCYoZAACAJShmAAAAlmBXJoAyJScnG/OHHnrI0Xk+++wzYz5s2DBjfv78eWN+5coVj6xmzZrGY/fv32/MO3bsaMwTEhKMOYCy3XXXXcb86tWrxnzTpk1BnCY0cccMAADAEhQzAAAAS1DMAAAALEExAwAAsATFDAAAwBIhuyvT23vxTZ8+3ZifPXvWmOfn5xvz119/3Zh/+eWXxvzkyZPGHKgKGjVqZMxdLpcx97b7csCAAcY8KyvLv8H+xY9//GNj3rZtW0fn2b59e7lnAaq69u3bG/O5c+ca83Xr1gVznCqFO2YAAACWoJgBAABYgmIGAABgCYoZAACAJShmAAAAlgjZXZkpKSnGvEWLFgE5/8yZM4355cuXjbm3XWih4IsvvjDm3v6O09PTgzkOLPTOO+8Y89tvv92Ye1snFy5cCNhM3zV27FhjHhEREbRrAtVVmzZtjHlsbKwxf/PNN4M5TpXCHTMAAABLUMwAAAAsQTEDAACwBMUMAADAEhQzAAAAS4Tsrkxv74mZlJRkzI8dO2bMv//97xvzzp07G/OePXsa827duhnzM2fOeGTNmjUzHutUYWGhMT937pwx9/Z+h96cPn3amLMrEzdlZmZWynXnzZvnkbVu3drROf73f//XUQ7gW0899ZQx9/b/BP7d8B13zAAAACxBMQMAALAExQwAAMASFDMAAABLUMwAAAAsEbK7Mnfv3u0o92bnzp2Ojq9Tp44xv+uuu4z5wYMHPbKuXbs6uqY3+fn5xvzEiRPG3NvO1Pj4eGOekZHh32BAgAwZMsSYL1u2zCOrWbOm8djs7GxjvmDBAmOel5fn43RA1eft/aeTk5ONubd/f65evRqokao87pgBAABYgmIGAABgCYoZAACAJShmAAAAlqCYAQAAWCJkd2VWlq+//tqYp6Wl+XwOpztHnRo5cqQx97aj9MiRI8b8zTffDNhMgD+87fzytgPTxNvzeM+ePX7NBFQn999/v6Pjvb1XM3zHHTMAAABLUMwAAAAsQTEDAACwBMUMAADAEhQzAAAAS7ArM4TVr1/fmK9atcqYh4WZe7jpfQcl6cKFC/4NBji0efNmY96/f3+fz/Haa68Z85/97Gf+jARAUocOHRwdn5KSEqRJqg/umAEAAFiCYgYAAGAJihkAAIAlKGYAAACWoJgBAABYgl2ZIWzOnDnGvF69esbc2/t8fv755wGbCbiVRo0aGfPu3bsb88jISGN+/vx5j+yZZ54xHnvlyhUfpwOqt27dunlkU6ZMMR7717/+1Zjv2rUroDNVR9wxAwAAsATFDAAAwBIUMwAAAEtQzAAAACzBL/+HgB49ehjz+fPnOzrP8OHDjfnRo0edjgT4ZePGjcY8ISHB0Xn+8Ic/eGQZGRl+zQTghr59+3pk8fHxxmN37txpzPPz8wM6U3XEHTMAAABLUMwAAAAsQTEDAACwBMUMAADAEhQzAAAAS7ArMwQMGjTImEdERBjz3bt3G/NPPvkkYDMBtzJs2DBj3rlzZ0fn+eCDD4z54sWLnY4EoAwdO3b0yNxut/HYDRs2BHucaos7ZgAAAJagmAEAAFiCYgYAAGAJihkAAIAlKGYAAACWYFemRaKjo435wIEDjfn169eNubcdawUFBf4NBnjh7T0uf/rTnxpzbzuJvTl06JAxv3LliqPzAPhWw4YNjfkPfvADj+zzzz83Hrtp06aAzoRvcccMAADAEhQzAAAAS1DMAAAALEExAwAAsATFDAAAwBLsyrTIvHnzjHmnTp2M+c6dO435vn37AjYTcCs//vGPjXnXrl0dnWfz5s3GnPfEBAJv8uTJxrx+/foe2Z/+9KcgT4Pv4o4ZAACAJShmAAAAlqCYAQAAWIJiBgAAYAmKGQAAgCXYlVkJBg8ebMx//vOfG/NLly4Z82XLlgVsJsAfTz75ZEDOM3fuXGPOe2ICgde8eXOfj/3666+DOAlMuGMGAABgCYoZAACAJShmAAAAlqCYAQAAWIJiBgAAYAl2ZQZZQkKCR/Zf//VfxmNr1KhhzHfs2GHM9+/f7/9ggEXi4+ONeUFBQdCumZub6+iaERERxrx27dqOrvu9733PmAdqh2tRUZExf/rpp415Xl5eQK6L0DFkyBCfj33nnXeCOAlMuGMGAABgCYoZAACAJShmAAAAlqCYAQAAWIJiBgAAYAl2ZQaItx2VO3fu9MhatmxpPDYjI8OYe3sPTaCqOHz4cIVf8+233zbmWVlZxrxBgwbGfMyYMQGbKZi+/PJLY/7ss89W8CSoKPfee68xb9iwYQVPAie4YwYAAGAJihkAAIAlKGYAAACWoJgBAABYgmIGAABgCXZlBkhiYqIx79Kli8/n8PZeed52awKVzdv7uD744IMVPIlzo0ePDur5CwsLjXlxcbGj82zdutWYp6enOzrPRx995Oh4hL6HHnrImHt7FYG//vWvHtmHH34Y0JlQNu6YAQAAWIJiBgAAYAmKGQAAgCUoZgAAAJagmAEAAFiCXZkONW/e3Ji/9957Pp9j3rx5xnzbtm1+zQRUlhEjRhjzp556yphHREQE5Lrt2rXzyAL1npWpqanG/NSpU47Os3HjRmN+/PhxpyMBtxQTE2PMBw0a5Og8GzZs8MiKior8mgn+444ZAACAJShmAAAAlqCYAQAAWIJiBgAAYAmKGQAAgCXYlenQjBkzjPm//du/+XyOPXv2GHO32+3XTIBtUlJSKvya48aNq/BrAjYoKCgw5l9//bUx9/b+qytWrAjYTPAfd8wAAAAsQTEDAACwBMUMAADAEhQzAAAAS1DMAAAALMGuTC/uvfdeY/7YY49V8CQAAHjnbVdm9+7dK3gSBAJ3zAAAACxBMQMAALAExQwAAMASFDMAAABLUMwAAAAswa5ML37wgx8Y81q1ajk6T0ZGhkd25coVv2YCAABVG3fMAAAALEExAwAAsATFDAAAwBIUMwAAAEtQzAAAACzBrswA+dvf/mbM+/Tp45FduHAh2OMAAIAQxB0zAAAAS1DMAAAALEExAwAAsATFDAAAwBIUMwAAAEu43G63u6yDLl26pNq1a1fEPIBfcnNzddttt1X2GI6wrmA71hUQeGWtK+6YAQAAWIJiBgAAYAmKGQAAgCUoZgAAAJbwqZj5sD8AqFSh+BwNxZlRvYTiczQUZ0b1UtZz1Kdidvny5YAMAwRLKD5HQ3FmVC+h+BwNxZlRvZT1HPXp5TKKi4t19uxZxcXFyeVyBWw4oLzcbrcuX76sxo0bKywstH4yz7qCrVhXQOD5uq58KmYAAAAIvtD6VggAAKAKo5gBAABYgmIGAABgCYoZAACAJShmAAAAlqCYAQAAWIJiBgAAYAmKGQAAgCUoZgAAAJagmAEAAFiCYgYAAGAJihkAAIAlKGYAAACWoJgBAABYgmIGAABgCYoZAACAJShmAAAAlqCYAQAAWIJiBgAAYAmKGQAAgCUoZgAAAJagmAEAAFiCYgYAAGCJSi1mhw8f1rRp05SYmKjo6GhFR0frjjvu0MyZM5Wenl6Zo5Wby+XSkiVLvH6+Z8+ecrlcZf651Tl8kZeXpyVLluiDDz7w+NySJUvkcrl0/vz5cl3D5M9//rPuuecexcTEqG7dupo8ebKys7MDfh14Yl1V3XV107Vr19S6dWu5XC7953/+Z9Cug2+xrqrmutq2bZsmTpyoDh06KCIiQi6XK6Dn90d4ZV149erVmjt3ru6880498cQTateunVwul44dO6b169era9euOnnypBITEytrxKBatWqVLl26VPLx9u3b9cwzz+iVV15RmzZtSvKmTZuW6zp5eXlaunSppBuLqyLs2bNHDzzwgAYPHqwtW7YoOztbTz/9tPr06aP09HRFRkZWyBzVEeuq6q6rf/Xzn/9cV69erfDrVlesq6q7rjZt2qT9+/erU6dOioyM1MGDByvkurdSKcVs7969mj17tgYPHqwNGzaoZs2aJZ/r3bu35syZo7ffflvR0dG3PE9eXp5iYmKCPW5QtG3bttTHx48flyS1b99eycnJXr8uFB7zvHnz1Lp1a23YsEHh4TeeYi1btlSPHj2UmpqqH/3oR5U8YdXEuqra6+qmTz/9VL/5zW/0+uuva/To0ZU9TpXHuqra6+r3v/+9wsJu/PBw7ty5VhSzSvlR5vLly1WjRg2tXr261JP8X40ePVqNGzcu+Xjy5MmqVauWjhw5ov79+ysuLk59+vSRJF24cEGzZ89WkyZNVLNmTbVq1UoLFy7UN998U/L1p06dksvl0quvvupxre/egr15y/Szzz7Tww8/rNq1a6tBgwaaOnWqcnNzS33tpUuXNH36dCUkJKhWrVoaOHCgTpw4UY6/nW/dnOMvf/mLRo0apTp16pR8R9azZ0/jdxSTJ09WixYtSh5zvXr1JElLly4tud08efLkUl/z1Vdflfk4ffXPf/5TBw4c0IQJE0pKmSR1795drVu31qZNm/w6L8rGuvJNKK6rm65fv66pU6dqzpw5t/wHEYHDuvJNqK6rm6XMJhV+x6yoqEhpaWlKTk5Wo0aNHH3t9evXNWzYMM2cOVPz589XYWGh8vPz1atXL2VkZGjp0qVKSkrSRx99pOeee06HDh3S9u3b/Z515MiRGjNmjKZNm6YjR45owYIFkqTU1FRJktvt1vDhw7Vv3z4tWrRIXbt21d69e/XAAw/4fU2TESNGaOzYsZo1a5ajH180atRIO3fu1MCBAzVt2jQ9+uijklTy5L+prMcp3Vh0S5cuVVpa2i1vMR89elSSlJSU5PG5pKQk7d271+f54TvWlXOhtK5uWrZsma5evapf/OIXOnfunM8zwz+sK+dCcV3ZpsKL2fnz53Xt2jU1b97c43NFRUVyu90lH9eoUaPUL+IVFBRo0aJFmjJlSkm2evVqHT58WG+99VbJbf1+/fqpVq1aevrpp7Vr1y7169fPr1mnTZumefPmSZL69u2rkydPKjU1VWvWrJHL5dK7776rtLQ0rVixQo8//njJtWvWrKmFCxf6dU2TSZMmlfzc3YnIyEh16dJF0o2f/Xfr1s14XFmPU7rxXcV3/3uY5OTkSJLi4+M9PhcfH1/yeQQW68q5UFpXknTo0CGlpKTonXfeUWxsLMWsArCunAu1dWUjq+7hdenSRRERESV/fvnLX3ocM3LkyFIfv//++4qNjdWoUaNK5Tdvf+7evdvveYYNG1bq46SkJOXn55fsLkxLS5MkjR8/vtRx48aN8/uaJt99zIFW1uOUpEWLFqmwsFD333+/T+f0tiBCdaGEMtaVWSitq8LCQk2dOlVjxozRgAEDgjIvnGFdmYXSurJVhd8xq1u3rqKjo5WZmenxuTfeeEN5eXnKysry+MuXpJiYGN12222lspycHDVs2NDjH/z69esrPDy8XHdoEhISSn18czfhtWvXSq4dHh7ucVzDhg39vqaJ01voTpX1OP05l+nv/cKFC8Y7aSg/1pVzobSufv3rX+sf//iH3nrrLV28eFGSSnbJ5efn6+LFi4qLi1ONGjXKNzRKYV05F0rrylYVfsesRo0a6t27t9LT05WVlVXqc23btlVycrI6dOhg/FrT3ZaEhAR99dVXpW4pS1J2drYKCwtVt25dSVJUVJQklfoFS8lcIHyVkJCgwsJCj3N8+eWXfp/TxPS4o6KiPB6LpKC+dpIv2rdvL0k6cuSIx+eOHDlS8nkEFuvKuVBaV0ePHlVubq7uuOMO1alTR3Xq1FHHjh0l3XjpjDp16hjXHMqHdeVcKK0rW1XKjzIXLFigoqIizZo1SwUFBeU6V58+fXTlyhVt3ry5VP7aa6+VfF6SGjRooKioKB0+fLjUcVu2bPH72r169ZIkvf7666XyN954w+9z+qpFixY6ceJEqSd7Tk6O9u3bV+q4iv5uokmTJrr77rv1hz/8QUVFRSX5/v379fnnn2vEiBEVMkd1xLoqP1vX1fz585WWllbqz/r16yVJs2bNUlpamm6//fYKmaW6YV2Vn63rylaV8jpmPXr00MqVK/XYY4+pc+fOmjFjhtq1a6ewsDBlZWVp48aNkuRxG9hk4sSJWrlypSZNmqRTp06pQ4cO+vjjj7V8+XINGjRIffv2lXSjxT/yyCNKTU1VYmKiOnbsqE8//bRcT8r+/fvrvvvu01NPPaWrV68qOTlZe/fu1bp16/w+p68mTJig1atX65FHHtH06dOVk5OjlJQUj7+zuLg4NW/eXFu2bFGfPn0UHx+vunXrlmxR9tWyZcu0bNky7d69u8yf2z///PPq16+fRo8erdmzZys7O1vz589X+/btS/0iLAKLdVV+tq6rNm3alHohT+nGywtIUmJiYkjuPAsVrKvys3VdSVJmZqYOHDggScrIyJAkbdiwQdKNQlkZL0tTaa/8P2vWLN1zzz1asWKFfvWrX+ns2bNyuVxq2rSpunfvrt27d6t3795lnicqKkppaWlauHChXnjhBZ07d05NmjTRT37yEy1evLjUsTd/OTMlJUVXrlxR7969tW3bNsf/0W8KCwvT1q1b9eSTTyolJUXXr19Xjx49tGPHDo//iQZajx49tHbtWv3Hf/yHHnzwQbVq1UqLFy/Wjh07PN7OYs2aNZo3b56GDRumb775RpMmTTK+Ps6tFBcXe+xC8qZnz57asWOHFi1apKFDhyomJkZDhgzRCy+8wKv+BxnrqnxsXleoPKyr8rF5XaWlpXncMLi5Y9afaweCy83/EQAAAKxg1ctlAAAAVGcUMwAAAEtQzAAAACxBMQMAALAExQwAAMASFDMAAABL+PQ6ZsXFxTp79qzi4uJ4E2pYxe126/Lly2rcuLHCwkLr+wzWFWzFugICz9d15VMxO3v2rJo1axaw4YBAO3PmjJo2bVrZYzjCuoLtWFdA4JW1rnz6ViguLi5gAwHBEIrP0VCcGdVLKD5HQ3FmVC9lPUd9KmbcDobtQvE5Goozo3oJxedoKM6M6qWs52ho/fIAAABAFUYxAwAAsATFDAAAwBIUMwAAAEtQzAAAACxBMQMAALAExQwAAMASFDMAAABLUMwAAAAsQTEDAACwBMUMAADAEhQzAAAAS1DMAAAALEExAwAAsATFDAAAwBIUMwAAAEtQzAAAACxBMQMAALAExQwAAMASFDMAAABLUMwAAAAsEV7ZA1QVsbGxxvyFF17wyGbOnGk89uDBg8Z89OjRxjwzM9PH6QAAQCjgjhkAAIAlKGYAAACWoJgBAABYgmIGAABgCYoZAACAJdiVGSCNGjUy5tOnT/fIiouLjcd26dLFmA8ZMsSYr1y50sfpADt07tzZmP/xj3805i1atAjiNIHRv39/Y37s2DFjfubMmWCOA1SqoUOHGvOtW7ca87lz5xrzl19+2ZgXFRX5N1gI4Y4ZAACAJShmAAAAlqCYAQAAWIJiBgAAYAmKGQAAgCXYlelQvXr1jPnatWsreBIg9AwYMMCYR0ZGVvAkgeNtF9rUqVON+dixY4M5DlAhEhISjPmqVascnee3v/2tMU9NTTXm165dc3T+UMQdMwAAAEtQzAAAACxBMQMAALAExQwAAMASFDMAAABLsCvTi8cff9yYDx8+3JjffffdQZvlvvvuM+ZhYeZe/be//c2Yf/jhhwGbCbiV8HDz/1oGDRpUwZME38GDB435k08+acxjY2ON+dWrVwM2ExBs3v5datq0qaPzrF+/3pjn5+c7nqmq4I4ZAACAJShmAAAAlqCYAQAAWIJiBgAAYAmKGQAAgCXYlenFr371K2NeXFxcwZNII0aMcJRnZmYa8zFjxhhzb7vKAH/16tXLmN9zzz3GPCUlJZjjBFWdOnWMedu2bY15TEyMMWdXJmzk7X1sFy5cGJDzr1u3zpi73e6AnD8UcccMAADAEhQzAAAAS1DMAAAALEExAwAAsATFDAAAwBLVflfmjh07jLm396EMppycHGN+5coVY968eXNj3rJlS2P+6aefGvMaNWr4MB3gqX379sbc2/vfZWRkGPPly5cHbKaK9uCDD1b2CEDQdOjQwZh36dLF0XkKCwuN+Z/+9CfHM1V13DEDAACwBMUMAADAEhQzAAAAS1DMAAAALEExAwAAsES12ZV5//33G/M777zTmHt7T8xAvFfmyy+/bMzfe+89Y56bm2vMe/fubcydvofZj370I2P+0ksvOToPqp+f/exnxjw2NtaYDxw40Jh723lsk/j4eGPu7f8tlfG+ukCgjRw5MiDn8fbvGzxxxwwAAMASFDMAAABLUMwAAAAsQTEDAACwBMUMAADAElVuV2aLFi2M+f/8z/8Y87p16wbkupmZmcZ848aNHtnSpUuNx+bl5QXkmjNmzDDm9erVM+YpKSnGPCoqypj/9re/NeYFBQXGHKFv1KhRxnzQoEHG/OTJk8Y8PT09YDNVNG+7nb3tvvzggw+M+cWLFwM0ERB89913n6Pjr1+/bsydvlpAdcYdMwAAAEtQzAAAACxBMQMAALAExQwAAMASFDMAAABLVLldmeHh5ocUqN2Xe/bsMeZjx4415ufPnw/IdU287cp87rnnjPmLL75ozGNiYoy5t92aW7duNeYZGRnGHKFv9OjRxtzbc2fVqlXBHCeovO3sHj9+vDEvKioy5s8884wxZ/cybNW9e3efslu5evWqMT906JA/I1VL3DEDAACwBMUMAADAEhQzAAAAS1DMAAAALEExAwAAsESV25UZKN7e02/q1KnGPJi7L53ytmvS266yrl27BnMchJDatWsb827dujk6z0svvRSIcSqFt/ea9baz+9ixY8Y8LS0tYDMBFSEQ/xaE8tq3BXfMAAAALEExAwAAsATFDAAAwBIUMwAAAEtUm1/+Dwtz1kH//d//PUiTBJ/L5TLm3v4OnP7dLFmyxJhPmDDB0Xlgn8jISGPepEkTY75+/fpgjlMpEhMTHR1/9OjRIE0CVKzk5GSfj7148aIx55f/y487ZgAAAJagmAEAAFiCYgYAAGAJihkAAIAlKGYAAACWqHK7MmfNmmXMi4uLK3iSyjN06FBj3qlTJ2Pu7e/GW+5tVyZC3+XLl435oUOHjHlSUpIxj4+PN+YXLlzwa65gqF+/vjEfNWqUo/N8/PHHgRgHqDD33nuvMR83bpzP58jNzTXmX3zxhV8z4VvcMQMAALAExQwAAMASFDMAAABLUMwAAAAsQTEDAACwRJXbleltR2Ioq1evnjFv27atMf/pT38akOueO3fOmBcUFATk/LDPtWvXjHlGRoYxHzlypDHfvn27MX/xxRf9G8wH7du3N+atWrUy5i1atDDmbrfb0XWr045vVA0JCQnG3Mn7Ju/atStQ4+A7uGMGAABgCYoZAACAJShmAAAAlqCYAQAAWIJiBgAAYIkqtyuzKlq4cKExnzNnTkDOf+rUKWM+adIkY3769OmAXBehY/Hixcbc5XIZ88GDBxvz9evXB2ym7zp//rwx97bLsm7dugG57quvvhqQ8wAVxcn7wV68eNGYr169OkDT4Lu4YwYAAGAJihkAAIAlKGYAAACWoJgBAABYgmIGAABgCXZlWmTHjh3G/M477wzqdf/+978b848//jio10XoOH78uDH/4Q9/aMzvuusuY3777bcHaiQPGzZscHT82rVrjfn48eMdncfb+4sCla1p06bGfNy4cT6f44svvjDm6enpfs2EsnHHDAAAwBIUMwAAAEtQzAAAACxBMQMAALAExQwAAMASVW5Xprf37gsLc9ZBH3jgAUfH/+53vzPmjRs39vkc3mYsLi52NItTQ4cODer5Uf0cOnTIUV4Z/vGPfwTkPO3btzfmR48eDcj5AX91797dmDv593Dz5s0Bmga+4o4ZAACAJShmAAAAlqCYAQAAWIJiBgAAYAmKGQAAgCWq3K7Ml156yZinpKQ4Os+2bduMudMdkoHYURmoXZkvv/xyQM4DVAXednB7y71h9yVslZCQ4Oj48+fPe2QrVqwI1DjwEXfMAAAALEExAwAAsATFDAAAwBIUMwAAAEtQzAAAACxR5XZl/vGPfzTm8+bNM+b16tUL5jgBce7cOWN+7NgxYz5jxgxjnpWVFbCZgFDndrsd5UCoGTBggKPjT58+7ZHl5uYGahz4iDtmAAAAlqCYAQAAWIJiBgAAYAmKGQAAgCUoZgAAAJaocrsyMzMzjfnYsWON+fDhw435E088EaiRyu3ZZ5815itXrqzgSYCqIyoqytHx165dC9IkQPlEREQY88TEREfnyc/P98gKCgr8mgn+444ZAACAJShmAAAAlqCYAQAAWIJiBgAAYAmKGQAAgCWq3K5Mbz788ENH+XvvvWfMvb0P5dChQ4351q1bPbLf/e53xmNdLpcx//vf/27MAfhvypQpxvzixYvG/Be/+EUQpwH8V1xcbMzT09ONefv27Y35yZMnAzYT/McdMwAAAEtQzAAAACxBMQMAALAExQwAAMASFDMAAABLVJtdmU7t3LnTUQ4gtBw4cMCYv/jii8Y8LS0tmOMAfisqKjLmCxcuNOZut9uYHzx4MGAzwX/cMQMAALAExQwAAMASFDMAAABLUMwAAAAsQTEDAACwhMvtbXvGv7h06ZJq165dEfMAfsnNzdVtt91W2WM4wrqC7VhXQOCVta64YwYAAGAJihkAAIAlKGYAAACWoJgBAABYgmIGAABgCYoZAACAJShmAAAAlqCYAQAAWIJiBgAAYAmKGQAAgCUoZgAAAJagmAEAAFiCYgYAAGAJihkAAIAlKGYAAACWoJgBAABYwqdi5na7gz0HUC6h+BwNxZlRvYTiczQUZ0b1UtZz1Kdidvny5YAMAwRLKD5HQ3FmVC+h+BwNxZlRvZT1HHW5ffj2ori4WGfPnlVcXJxcLlfAhgPKy+126/Lly2rcuLHCwkLrJ/OsK9iKdQUEnq/ryqdiBgAAgOALrW+FAAAAqjCKGQAAgCUoZgAAAJagmAEAAFiCYgYAAGAJihkAAIAlKGYAAACW+H+bVfBbn519CwAAAABJRU5ErkJggg==",
      "text/plain": [
       "<Figure size 640x480 with 6 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt \n",
    "%matplotlib inline\n",
    "examples = enumerate(test_loader) \n",
    "batch_idx, (example_data, example_targets) = next(examples)\n",
    "fig = plt.figure() \n",
    "for i in range(6): \n",
    "    plt.subplot(2,3,i+1) \n",
    "    plt.tight_layout() \n",
    "    plt.imshow(example_data[i][0], cmap='gray', interpolation='none') \n",
    "    plt.title(\"Ground Truth: {}\".format(example_targets[i])) \n",
    "    plt.xticks([])\n",
    "    plt.yticks([])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "9c731fdb",
   "metadata": {},
   "outputs": [],
   "source": [
    "class Net(nn.Module): \n",
    "    \"\"\" \n",
    "    使用sequential构建网络，Sequential()函数的功能是将网络的层组合到一起\n",
    "    \"\"\"\n",
    "    def __init__(self, in_dim, n_hidden_1, n_hidden_2, out_dim): \n",
    "        super(Net, self).__init__() \n",
    "        self.layer1 = nn.Sequential(nn.Linear(in_dim, n_hidden_1),nn.BatchNorm1d(n_hidden_1)) \n",
    "        self.layer2 = nn.Sequential(nn.Linear(n_hidden_1, n_hidden_2),nn.BatchNorm1d (n_hidden_2)) \n",
    "        self.layer3 = nn.Sequential(nn.Linear(n_hidden_2, out_dim))\n",
    "    \n",
    "    def forward(self, x): \n",
    "        x = F.relu(self.layer1(x)) \n",
    "        x = F.relu(self.layer2(x)) \n",
    "        x = self.layer3(x)\n",
    "        return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "18ada756",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "cuda:0\n"
     ]
    }
   ],
   "source": [
    "#检测是否有可用的GPU，有则使用，否则使用CPU \n",
    "device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\") #实例化网络 \n",
    "print(device)\n",
    "model = Net(28 * 28, 300, 100, 10) \n",
    "model.to(device)\n",
    "\n",
    "# 定义损失函数和优化器 \n",
    "criterion = nn.CrossEntropyLoss()\n",
    "optimizer = optim.SGD(model.parameters(), lr=lr, momentum=momentum)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "5db48bc7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch: 0, Train Loss: 1.0291, Train Acc: 0.7823, Test Loss: 0.5430, Test Acc: 0.9004\n",
      "epoch: 1, Train Loss: 0.4813, Train Acc: 0.8999, Test Loss: 0.3479, Test Acc: 0.9256\n",
      "epoch: 2, Train Loss: 0.3508, Train Acc: 0.9196, Test Loss: 0.2729, Test Acc: 0.9367\n",
      "epoch: 3, Train Loss: 0.2856, Train Acc: 0.9320, Test Loss: 0.2245, Test Acc: 0.9476\n",
      "epoch: 4, Train Loss: 0.2431, Train Acc: 0.9403, Test Loss: 0.1975, Test Acc: 0.9540\n",
      "epoch: 5, Train Loss: 0.2220, Train Acc: 0.9458, Test Loss: 0.1964, Test Acc: 0.9527\n",
      "epoch: 6, Train Loss: 0.2189, Train Acc: 0.9472, Test Loss: 0.1924, Test Acc: 0.9535\n",
      "epoch: 7, Train Loss: 0.2171, Train Acc: 0.9466, Test Loss: 0.1905, Test Acc: 0.9547\n",
      "epoch: 8, Train Loss: 0.2142, Train Acc: 0.9481, Test Loss: 0.1885, Test Acc: 0.9540\n",
      "epoch: 9, Train Loss: 0.2122, Train Acc: 0.9478, Test Loss: 0.1836, Test Acc: 0.9562\n",
      "epoch: 10, Train Loss: 0.2091, Train Acc: 0.9489, Test Loss: 0.1865, Test Acc: 0.9554\n",
      "epoch: 11, Train Loss: 0.2106, Train Acc: 0.9478, Test Loss: 0.1831, Test Acc: 0.9559\n",
      "epoch: 12, Train Loss: 0.2098, Train Acc: 0.9485, Test Loss: 0.1849, Test Acc: 0.9560\n",
      "epoch: 13, Train Loss: 0.2093, Train Acc: 0.9485, Test Loss: 0.1824, Test Acc: 0.9562\n",
      "epoch: 14, Train Loss: 0.2082, Train Acc: 0.9494, Test Loss: 0.1844, Test Acc: 0.9567\n",
      "epoch: 15, Train Loss: 0.2080, Train Acc: 0.9489, Test Loss: 0.1827, Test Acc: 0.9556\n",
      "epoch: 16, Train Loss: 0.2081, Train Acc: 0.9486, Test Loss: 0.1836, Test Acc: 0.9559\n",
      "epoch: 17, Train Loss: 0.2074, Train Acc: 0.9494, Test Loss: 0.1822, Test Acc: 0.9563\n",
      "epoch: 18, Train Loss: 0.2080, Train Acc: 0.9493, Test Loss: 0.1842, Test Acc: 0.9553\n",
      "epoch: 19, Train Loss: 0.2101, Train Acc: 0.9494, Test Loss: 0.1859, Test Acc: 0.9559\n"
     ]
    }
   ],
   "source": [
    "# 开始训练 \n",
    "losses = [] \n",
    "acces = [] \n",
    "eval_losses = [] \n",
    "eval_acces = []\n",
    "for epoch in range(num_epoches): \n",
    "    train_loss = 0 \n",
    "    train_acc = 0 \n",
    "    model.train()\n",
    "    #动态修改参数学习率 \n",
    "    if epoch%5==0: \n",
    "        optimizer.param_groups[0]['lr']*=0.1\n",
    "    for img, label in train_loader: \n",
    "        img=img.to(device) \n",
    "        label = label.to(device) \n",
    "        img = img.view(img.size(0), -1) \n",
    "        # 前向传播 \n",
    "        out = model(img) \n",
    "        loss = criterion(out, label) \n",
    "        # 反向传播 \n",
    "        optimizer.zero_grad() \n",
    "        loss.backward() \n",
    "        optimizer.step() \n",
    "        # 记录误差 \n",
    "        train_loss += loss.item() \n",
    "        # 计算分类的准确率 \n",
    "        _, pred = out.max(1) \n",
    "        num_correct = (pred == label).sum().item() \n",
    "        acc = num_correct / img.shape[0] \n",
    "        train_acc += acc\n",
    "    losses.append(train_loss / len(train_loader)) \n",
    "    acces.append(train_acc / len(train_loader)) \n",
    "    # 在测试集上检验效果 \n",
    "    eval_loss = 0 \n",
    "    eval_acc = 0\n",
    "    # 将模型改为预测模式 \n",
    "    model.eval() \n",
    "    for img, label in test_loader: \n",
    "        img=img.to(device) \n",
    "        label = label.to(device) \n",
    "        img = img.view(img.size(0), -1) \n",
    "        out = model(img) \n",
    "        loss = criterion(out, label) \n",
    "        # 记录误差 \n",
    "        eval_loss += loss.item() \n",
    "        # 记录准确率 \n",
    "        _, pred = out.max(1) \n",
    "        num_correct = (pred == label).sum().item() \n",
    "        acc = num_correct / img.shape[0] \n",
    "        eval_acc += acc\n",
    "\n",
    "    eval_losses.append(eval_loss / len(test_loader)) \n",
    "    eval_acces.append(eval_acc / len(test_loader)) \n",
    "    print('epoch: {}, Train Loss: {:.4f}, Train Acc: {:.4f}, Test Loss: {:.4f}, Test Acc: {:.4f}'.format(epoch, train_loss / len(train_loader), train_acc / len(train_loader),\n",
    "        eval_loss / len(test_loader), eval_acc / len(test_loader)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f57096d9",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
